package authpublish

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"time"

	"blogcenter/internal/config"
	"blogcenter/internal/middleware"
	"blogcenter/internal/model"
	"blogcenter/internal/svc"
	"blogcenter/internal/types"
	"blogcenter/internal/utils"

	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpc"
	"gorm.io/gorm"
)

type PublishBlogLogic struct {
	logx.Logger
	ctx         context.Context
	svcCtx      *svc.ServiceContext
	GorseClient *utils.GorseClient
}

func NewPublishBlogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PublishBlogLogic {
	return &PublishBlogLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *PublishBlogLogic) PublishBlog(req *types.BlogRequest) (*types.BlogDetailResponse, error) {
	// 1. 获取当前用户ID
	userId, err := l.getUserId()
	if err != nil {
		return nil, err
	}

	// 2. 解析内容中的标签
	tags := utils.ParseTags(req.Content)

	// 3. 创建博客文章
	blog := &model.BlogInfo{
		UserId:     userId,
		Title:      req.Title,
		Content:    req.Content,
		Category:   req.Category,
		JoyNum:     req.JoyNum,
		JoyFeeling: req.JoyFeeling,
		Place:      req.Place,
	}

	var blogId uint
	// 开启事务
	err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
		// 使用事务版本的模型
		blogModel := model.NewBlogModel(tx)
		tagModel := model.NewTagModel(tx)

		// 创建博客
		id, err := blogModel.Create(l.ctx, blog)
		blogId = id
		if err != nil {
			return err
		}

		// 处理标签
		for _, tagName := range tags {
			// 查找或创建标签
			tag, err := tagModel.FindOrCreate(l.ctx, tagName)
			if err != nil {
				return err
			}

			// 创建标签映射
			err = tagModel.CreateTag(l.ctx, &model.TagMap{
				BlogId:    int(blogId),
				TagId:     int(tag.ID),
				TagDetail: tagName,
			})
			if err != nil {
				return err
			}

			// 更新标签的博客计数
			err = tagModel.IncrementBlogNum(l.ctx, tag.ID)
			if err != nil {
				return err
			}
		}

		// 如果有图片，创建图片记录
		if req.Photo != nil && len(req.Photo.Url) > 0 {
			if err := blogModel.CreateImages(l.ctx, blogId, req.Photo.Url); err != nil {
				return err
			}
		}

		return nil
	})

	if err != nil {
		logx.Errorf("创建博客失败: %v", err)
		return nil, errors.New("创建博客失败")
	}

	// 异步同步到Gorse推荐系统
	go func() {
		// 创建新的context避免使用已取消的请求context
		ctx := context.Background()
		err := l.svcCtx.GorseClient.CreatBlogGorse(ctx, *req, tags, int(blogId))
		if err != nil {
			logx.Errorf("同步博客到Gorse失败: %v", err)
		}
	}()

	// 异步同步到搜索系统
	go func() {
		// 创建新的context避免使用已取消的请求context
		ctx := context.Background()
		err := l.svcCtx.SearchClient.IndexBlog(ctx, &utils.Blog{
			Id:         int(blogId),
			UserId:     blog.UserId,
			Title:      blog.Title,
			Content:    blog.Content,
			Category:   blog.Category,
			JoyNum:     blog.JoyNum,
			JoyFeeling: blog.JoyFeeling,
			Place:      blog.Place,
			Tags:       tags,
			CreateTime: blog.CreatedAt.Format("2006-01-02 15:04:05"),
		})
		logx.Infof("开始同步博客到搜索系统...")
		if err != nil {
			logx.Errorf("同步博客到搜索系统失败: %v", err)
		}
	}()

	// 加积分
	_, err = l.addCredit(int(userId))

	if err != nil {
		logx.Errorf("添加积分失败: %v", err)
	}

	// 4. 返回创建结果
	return &types.BlogDetailResponse{
		BaseResponse: types.BaseResponse{
			Code:    200,
			Message: "创建成功",
		},
		Data: types.Blog{
			Id:         int(blog.ID),
			Title:      blog.Title,
			Content:    blog.Content,
			Photo:      types.PhotoData{Url: req.Photo.Url},
			CreateTime: blog.CreatedAt.Format("2006-01-02 15:04:05"),
			Category:   blog.Category,
			UserId:     userId,
		},
	}, nil
}

func (l *PublishBlogLogic) getUserId() (int, error) {
	// 从ctx中获取用户ID，这里假设使用了JWT中间件
	userIdStr, ok := l.ctx.Value(middleware.UserIdKey).(int)
	if !ok {
		return 0, errors.New("获取用户信息失败")
	}
	if userIdStr == 0 {
		return 0, errors.New("未授权访问")
	}

	userId := userIdStr

	return userId, nil
}

func (l *PublishBlogLogic) addCredit(userID int) (*types.BaseResponse, error) {
	// 1. 定义响应结构体
	type addRequest struct {
		UserID    int    `json:"userId"`
		Credit    int    `json:"credit"`
		Operation string `json:"operation"`
	}
	add := addRequest{
		UserID:    userID,
		Credit:    2,
		Operation: "add",
	}
	// 确保context不为nil
	if l.ctx == nil {
		l.ctx = context.Background()
		logx.WithContext(l.ctx).Errorf("context为nil，使用background context")
	}
	cfg := config.GetBaseConfig()
	consulURL := fmt.Sprintf("http://%s:%s", cfg.Consul.Host, "/v1/health/service/user-api?passing")
	// 2. 从Consul获取user-api服务地址
	// consulURL := "http://127.0.0.1:8500/v1/health/service/user-api?passing"
	consulResp, err := httpc.Do(l.ctx, "GET", consulURL, nil)
	if err != nil {
		logx.WithContext(l.ctx).Errorf("consul请求失败, error: %v", err)
		return nil, fmt.Errorf("获取服务地址失败: %v", err)
	}
	defer consulResp.Body.Close()

	if consulResp.StatusCode != http.StatusOK {
		body, _ := ioutil.ReadAll(consulResp.Body)
		logx.WithContext(l.ctx).Errorf("consul返回非200状态码, status: %d, body: %s",
			consulResp.StatusCode, string(body))
		return nil, fmt.Errorf("consul返回错误状态码: %d", consulResp.StatusCode)
	}

	var services []struct {
		Service struct {
			Address string `json:"Address"`
			Port    int    `json:"Port"`
		} `json:"Service"`
	}

	consulBody, err := ioutil.ReadAll(consulResp.Body)
	if err != nil {
		logx.WithContext(l.ctx).Errorf("读取consul响应体失败, error: %v", err)
		return nil, fmt.Errorf("读取服务地址失败: %v", err)
	}

	if err := json.Unmarshal(consulBody, &services); err != nil {
		logx.WithContext(l.ctx).Errorf("解析consul响应失败, error: %v, body: %s",
			err, string(consulBody))
		return nil, fmt.Errorf("解析服务地址失败: %v", err)
	}

	if len(services) == 0 {
		logx.WithContext(l.ctx).Errorf("无可用user-api服务实例")
		return nil, fmt.Errorf("无可用服务实例")
	}

	// 随机选择一个实例
	rand.Seed(time.Now().UnixNano())
	instance := services[rand.Intn(len(services))]
	baseURL := fmt.Sprintf("http://%s:%d", instance.Service.Address, instance.Service.Port)

	// 3. 构建请求URL
	// url := fmt.Sprintf("%s/api/user/info/%d", baseURL, userID)

	// 4. 将结构体序列化为 JSON
	jsonData, err := json.Marshal(add)
	if err != nil {
		logx.WithContext(l.ctx).Errorf("JSON序列化失败, error: %v", err)
		return nil, fmt.Errorf("请求参数错误: %v", err)
	}

	// 创建标准 HTTP 请求
	req, err := http.NewRequest(
		"POST",
		baseURL+"/api/baseuser/add",
		bytes.NewBuffer(jsonData), // 使用原始 jsonData
	)
	if err != nil {
		return nil, err
	}

	// 设置 Header
	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	client := &http.Client{}
	resp, _ := client.Do(req.WithContext(l.ctx))

	// 5. 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		body, _ := ioutil.ReadAll(resp.Body)
		logx.WithContext(l.ctx).Errorf("用户服务返回非200状态码, userID: %d, status: %d, body: %s",
			userID, resp.StatusCode, string(body))
		return nil, fmt.Errorf("用户服务返回错误状态码: %d", resp.StatusCode)
	}

	// 6. 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logx.WithContext(l.ctx).Errorf("读取响应体失败, userID: %d, error: %v", userID, err)
		return nil, fmt.Errorf("读取响应体失败: %v", err)
	}

	// 7. 解析JSON
	var result types.BaseResponse
	if err := json.Unmarshal(body, &result); err != nil {
		logx.WithContext(l.ctx).Errorf("解析用户信息响应失败, userID: %d, error: %v, body: %s",
			userID, err, string(body))
		return nil, fmt.Errorf("解析用户信息响应失败: %v", err)
	}

	// 8. 检查业务状态码
	if result.Code != 200 {
		logx.WithContext(l.ctx).Errorf("用户服务返回业务错误, userID: %d, code: %d, message: %s",
			userID, result.Code, result.Message)
		return nil, fmt.Errorf("用户服务错误: %s", result.Message)
	}

	// 9. 返回信息
	return &types.BaseResponse{
		Code:    result.Code,
		Message: result.Message,
	}, nil
}